package com.milloc.db.util;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.TransactionIsolationLevel;

import java.util.ArrayList;
import java.util.List;

import static com.google.common.base.Preconditions.checkState;

/**
 * 多数据源事务
 *
 * @author gongdeming
 * @create 2019-09-03
 */
public class MultiTransactionUtil {
    private static final ThreadLocal<TransactionIsolationLevel> TRANSACTION_ISOLATION_LEVEL = new ThreadLocal<>();
    private static final ThreadLocal<List<SqlSession>> SQL_SESSIONS = ThreadLocal.withInitial(ArrayList::new);

    public static void openTransaction() {
        openTransaction(TransactionIsolationLevel.READ_COMMITTED);
    }

    public static void openTransaction(TransactionIsolationLevel level) {
        TRANSACTION_ISOLATION_LEVEL.set(level);
    }

    /**
     * 支持事务
     *
     * @param sqlSessionFactory sqlSessionFactory
     * @return SqlSession
     */
    public static SqlSession getSqlSession(SqlSessionFactory sqlSessionFactory) {
        if (TRANSACTION_ISOLATION_LEVEL.get() != null) {
            SqlSession sqlSession = sqlSessionFactory.openSession(TRANSACTION_ISOLATION_LEVEL.get());
            SQL_SESSIONS.get().add(sqlSession);
            return sqlSession;
        }
        return sqlSessionFactory.openSession();
    }

    public static void closeSqlSession(SqlSession sqlSession) {
        if (!SQL_SESSIONS.get().contains(sqlSession)) {
            sqlSession.close();
        }
    }

    public static void commitAll() {
        checkState(TRANSACTION_ISOLATION_LEVEL.get() != null);
        SQL_SESSIONS.get().forEach(SqlSession::commit);
        clear();
    }

    public static void rollbackAll() {
        checkState(TRANSACTION_ISOLATION_LEVEL.get() != null);
        SQL_SESSIONS.get().forEach(SqlSession::rollback);
        clear();
    }

    private static void clear() {
        TRANSACTION_ISOLATION_LEVEL.set(null);
        SQL_SESSIONS.get().forEach(SqlSession::close);
        SQL_SESSIONS.get().clear();
    }
}
